<template>
  <div>
    <el-row :gutter="20">
      <el-col :span="6"><div class="grid-content bg-purple">
        <el-switch
          style="display: block"
          v-model="draggable_switch"
          active-color="#13ce66"
          inactive-color="#ff4949"
          active-text="开启拖拽"
          inactive-text="关闭拖拽">
        </el-switch>
      </div></el-col>

      <el-col :span="6"><div class="grid-content bg-purple">
        <el-button type="danger"
                   @click="batchDelete">批量删除</el-button>
      </div>
      </el-col>
    </el-row>
    <el-tree
      :data="menus"
      :props="defaultProps"
      @node-click="handleNodeClick"
      :expand-on-click-node="false"
      node-key="catId"
      show-checkbox
      :default-expanded-keys="expendKey"
      :draggable="draggable_switch"
      :allow-drop="allowDrop"
      @node-drop="handleDrop"
      ref="menuTree"
    >
    <span class="custom-tree-node" slot-scope="{ node, data }">
        <span>{{ node.label }}</span>

        <span>
<!--          判断为无子菜单才可显示 append-->
          <el-button v-if="node.level <= 2"
                     type="text"
                     size="mini"
                     @click="() => append(data)">
            Append
          </el-button>
          <el-button type="primary" icon="el-icon-edit"
                     size="mini"
                     @click="() => edit(data)">
          </el-button>
          <!--          判断为无子菜单，才可删除-->
          <el-button v-if="node.level === max_level"
                     type="danger"
                     icon="el-icon-delete"
                     size="small" round
                     @click="() => remove(node, data)">

          </el-button>
        </span>
      </span>
    </el-tree>

    <!-- Form -->
    <el-dialog :title="dialog_title" :visible.sync="dialogFormVisible">
      <el-form :model="category">
        <el-form-item label="名称" :label-width="formLabelWidth">
          <el-input v-model="category.name" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="图标" :label-width="formLabelWidth">
          <el-input v-model="category.icon" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="计量单位" :label-width="formLabelWidth">
          <el-input v-model="category.productUnit" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="数量" :label-width="formLabelWidth">
          <el-input v-model="category.productCount" autocomplete="off"></el-input>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogFormVisible = false">取 消</el-button>
        <el-button type="primary" @click="()=>submit()">确 定</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
export default {
  data () {
    return {
      menus: [],
      expendKey: [],
      // defaultProps 存放组件的 参数: 响应key
      defaultProps: {
        label: 'name',
        children: 'childList'
      },
      category: {
        catId: null,
        name: '',
        parentCid: 0,
        showStatus: 1,
        sort: 0,
        catLevel: 0,
        icon: null,
        productUnit: null,
        productCount: null
      },
      dialogFormVisible: false,
      formLabelWidth: '120px',
      add_edit: null,  // 0 为add, 1为edit,
      dialog_title: '',
      max_level: 3,
      updateNodes: [], //存放拖拽更新的节点,
      draggable_switch: false,
      pCid: 0 // 批量拖拽更新后要展开的node
    }
  },
  methods: {
    handleNodeClick (data) {
      console.log('handleNodeClick',data);
    },
    getMenus () {
      this.$http({
        url: this.$http.adornUrl('/product/category/list/tree'),
        method: 'get',
      }).then((response) => {
        this.menus = response.data.data;
        console.log('response',this.menus);
      }).catch(() => {
        console.log("=========error==========")
        this.$message({
          type: 'error',
          message: '网络异常'
        });
      })
    },

    append (data) {
      console.log('append' ,data)
      this.dialogFormVisible = true;
      this.dialog_title = "添加"
      this.add_edit = 0;

      // 需要计算的属性
      this.category.catLevel = data.catLevel*1+1;
      this.category.parentCid = data.catId;
      console.log('parentCid',this.category.parentCid)

      // 避免更新操作后 vue的category对象缓存,只将要展示的内容回复空值
      this.category.name = null
      this.category.icon = null;
      this.category.productUnit = null
      this.category.productCount = 0;
      this.category.showStatus = 1;
      this.category.sort = 0;
    },

    edit (data) {
      console.log('编辑的数据', data)
      this.add_edit = 1;
      this.dialog_title = '编辑'
      this.$http({
        url: this.$http.adornUrl(`/product/category/info/${data.catId}`),
        method: 'get',
      }).then((response) => {
        console.log('category', response.data.data)
        this.category = response.data.data
        console.log('Vue.category', this.category)
      }).catch(()=>{
        console.log("=========error==========")
        this.$message({
          type: 'error',
          message: '网络异常'
        })
      })

      this.dialogFormVisible = true
    },

    submit (){
      if(this.add_edit === 0){
        // 添加 category
        this.addNewCategory()
      }else if (this.add_edit === 1){
        // 更新 category
        this.editCategory()
      }
      this.dialogFormVisible=false;
    },

    // 添加三级分类
    addNewCategory () {
      console.log('添加的数据', this.category)
      let temp = this.category.parentCid
      this.$http({
        url: this.$http.adornUrl('/product/category/save'),
        method: 'post',
        data: this.$http.adornData(this.category, false)
      }).then(({res})=>{
        this.$message({
          type: 'success',
          message: '添加成功'
        });
        this.getMenus();
        this.expendKey = [ temp ]
        console.log('afterAdd_category',temp)
      }).catch(() => {
        console.log("=========error==========")
        this.$message({
          type: 'error',
          message: '网络异常'
        });
      })

    },

    // 修改的 category
    editCategory () {
      console.log('add_edit', this.add_edit)
      let temp = this.category.parentCid
      // 包装要更新的字段，主键必须添加进去
      const catId = this.category.catId
      const name = this.category.name
      const icon = this.category.icon
      const productUnit = this.category.productUnit
      const productCount = this.category.productCount
      const post_category = {catId,name,icon,productUnit,productCount}
      console.log('提交编辑的category', post_category)

      this.$http({
        url: this.$http.adornUrl('/product/category/update'),
        method: 'post',
        data: this.$http.adornData(post_category, false)
      }).then(({res})=>{
        this.$message({
          type: 'success',
          message: '成功'
        });
        this.getMenus();
        this.expendKey = [ temp ]
        console.log('afterSubmit_category',temp)
      }).catch(() => {
        console.log("=========error==========")
        this.$message({
          type: 'error',
          message: '网络异常'
        });
      })

    },

    remove (node, data) {
      console.log("remove-node", node, data)
      var IDs = [data.catId];

      this.$confirm(`此操作将删除【${data.name}】, 是否继续?`, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        //向后端发起删除请求
        this.$http({
          url: this.$http.adornUrl('/product/category/delete'),
          method: 'post',
          data: this.$http.adornData(IDs, false
          )
        }).then(({res}) => {
          console.log(res)
          //刷新
          this.getMenus();
          this.$message({
            message: '恭喜你，删除成功',
            type: 'success'
          });

          // 删除后可能会造成菜单树闭合，而实际是不能闭合的,需要展开删除的父亲菜单
          this.expendKey=[ node.parent.data.catId ]

        })
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        })
      })
    },

    allowDrop(draggingNode, dropNode, type) {
      //console.log('选中Node:',draggingNode,'插入Node:', dropNode, 'type',type)
      let draggingNodeLeve = this.levelCount(draggingNode)
      let dropNodeLeve
      //同级调换顺序，找父Node的层级
      if(type === 'prev'){
        dropNodeLeve = dropNode.parent.level
      }
      if(type === 'next'){
        dropNodeLeve = dropNode.parent.level
      }

      //插入
      if(type === 'inner'){
        dropNodeLeve = dropNode.level
      }
      //console.log('选中Node所包含的层数:',draggingNodeLeve,'插入Node已层数:', dropNodeLeve, 'type',type)
      if(draggingNodeLeve + dropNodeLeve <= this.max_level){
        return true
      }else{
        return false
      }
    },

    // 计算 node 的层数
    levelCount( menuNode ) {
      console.log("开始计算层数", menuNode)
      let count = 0

      let items = []
      items.push(menuNode)

      while (items.length > 0 ){
        let temp = items.length
        for (let i = 0; i < temp; i++) {
          let head = items.shift()
          for(let j=0; j<head.childNodes.length; j++){
            items.push(head.childNodes[j])
          }
        }
        count++
      }
      return count
    },

    handleDrop(draggingNode, dropNode, dropType, ev) {
      console.log(draggingNode.label,'draggingNode',draggingNode, dropNode.label,'拖拽后',dropNode,'dropType',dropType);
      // 1、获取当前最新父节点 ID
      let pCid = 0
      let siblings = []  // 保存拖拽后的同级兄弟节点
      if(dropType === 'before' || dropType === 'after'){
        pCid = dropNode.data.parentCid === undefined ? 0 : dropNode.data.parentCid
        siblings = dropNode.parent.childNodes
      }else {
        pCid = dropNode.data.catId
        siblings = dropNode.childNodes
      }
      this.pCid = pCid

      //2、当前拖拽的最新排序，需要修改 sort值
      for (let i = 0; i < siblings.length; i++) {
        //遍历到了自己
        if(draggingNode.data.catId === siblings[i].data.catId){
          //遍历到正在拖拽的node，还需要修改 parentCid，自己的和自己所有子节点的 catLevel
          let new_level = draggingNode.level
          if(siblings[i].level !== draggingNode.level){
            //当前节点层级发生改变，及 dropType == inner
            new_level = siblings[i].level
            //修改当前拖拽node的所有子node的层级数
            this.updateChildNodeLevel(siblings[i])
          }
          this.updateNodes.push({catId: siblings[i].data.catId,
            sort: i, parentCid: pCid,
            catLevel: new_level
          })
          //遍历tuo
        }else{
          this.updateNodes.push({catId: siblings[i].data.catId, sort: i})
        }
      }

      console.log('更新Node', this.updateNodes)
      this.$http({
        url: this.$http.adornUrl('/product/category/update/sort'),
        method: 'post',
        data: this.$http.adornData(this.updateNodes, false)
      }).then(({res})=>{
        this.$message({
          type: 'success',
          message: '菜单修改成功'
        });
      }).catch(() => {
        console.log("=========error==========")
        this.$message({
          type: 'error',
          message: '网络异常'
        });
      })
      //this.getMenus();
      this.updateNodes = []
      this.expendKey = [pCid]
      this.pCid = 0
    },

    updateChildNodeLevel(node){
      if(node.childNodes.length >0 ){
        for (let i = 0; i < node.childNodes.length; i++) {
          let cData = node.childNodes[i].data
          console.log("changeLevel", {catId: cData.catId, catLevel: node.childNodes[i].level})
          this.updateNodes.push({catId: cData.catId, catLevel: node.childNodes[i].level})
          this.updateChildNodeLevel(node.childNodes[i])
        }
      }
    }
    ,
    updateDrag(){

    },

    batchDelete(){
      let checkedNodes = this.$refs.menuTree.getCheckedNodes()
      console.log('被选中的Nodes', checkedNodes)
      let post = []
      let names = []
      for (let i = 0; i < checkedNodes.length; i++) {
        post.push(checkedNodes[i].catId)
        names.push(checkedNodes[i].name)
      }
      this.$confirm(`此操作将删除【${names}】, 是否继续?`, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        //向后端发起删除请求
        this.$http({
          url: this.$http.adornUrl('/product/category/delete'),
          method: 'post',
          data: this.$http.adornData(post, false
          )
        }).then(({res}) => {
          this.$message({
            type: 'success',
            message: '批量删除成功'
          });
        })
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        })
      })
      this.getMenus()
    }
  },
  created () {
    this.getMenus()
  },
}
</script>

<style>

  .custom-tree-node {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size: 14px;
    padding-right: 8px;
  }

</style>
